package com.peans.common.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.google.common.base.Throwables;

/**
 * 包 名: com.hongma.homa.utils
 * 描 述:
 * 创建人: nickfeng
 * 创建日期: 2015/9/30
 */
public final class ReflectUtils {
	
	private ReflectUtils(){
		
	}
	
	
	public static Field findField(Class<?> clazz,String name){
		Assert.hasLength(name);
		return ReflectionUtils.findField(clazz, name);
	}
	
	public static void setField(String name, Object target, Object value){
		Field field = findField(target.getClass(), name);
		ReflectionUtils.setField(field, target, value);
	}
	
	public static Object getField(String name, Object target, Object value){
		Field field = findField(target.getClass(), name);
		return ReflectionUtils.getField(field, target);
	}
	
	public static Object invokeMethod(String method,Class<?>[] paramTypes, Object target, Object... args){
		Method m = ReflectionUtils.findMethod(target.getClass(), method, paramTypes);
		return ReflectionUtils.invokeMethod(m, target, args);
	}
	
	public static Object invokeMethod(String method,Object target){
		Method m = ReflectionUtils.findMethod(target.getClass(), method);
		return ReflectionUtils.invokeMethod(m, target);
	}
	
	public static void handleReflectionException(Exception ex){
		ReflectionUtils.handleReflectionException(ex);
	}
	
	
	 public static Map<String, Field> getClassFields(Class<?> clazz) {
	        return getClassFields(clazz, false);
	  }
	
	 public static Map<String, Field> getAllClassFields(Class<?> clazz) {
	        return getClassFields(clazz, true);
	  }
	 
    /**
     * 获取类实例的属性值
     *
     * @param clazz              类名
     * @param includeParentClass 是否包括父类的属性值
     * @return 类名.属性名=属性类型
     */
    public static Map<String, Field> getClassFields(Class<?> clazz, boolean includeParentClass) {
        Map<String, Field> map = new HashMap<String, Field>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            map.put(clazz.getName() + "." + field.getName(), field);
        }
        if (includeParentClass){
            getParentClassFields(map, clazz.getSuperclass());
        }
        return map;
    }

    /**
     * 获取类实例的父类的属性值
     *
     * @param map   类实例的属性值Map
     * @param clazz 类名
     * @return 类名.属性名=属性类型
     */
    private static Map<String, Field> getParentClassFields(Map<String, Field> map, Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            map.put(clazz.getName() + "." + field.getName(), field);
        }
        if (clazz.getSuperclass() == null) {
            return map;
        }
        getParentClassFields(map, clazz.getSuperclass());
        return map;
    }

    /**
     * 获取类实例的方法
     *
     * @param clazz              类名
     * @param includeParentClass 是否包括父类的方法
     * @return List
     */
    public static List<Method> getMothds(Class<?> clazz, boolean includeParentClass) {
        List<Method> list = new ArrayList<Method>();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            list.add(method);
        }
        if (includeParentClass) {
            getParentClassMothds(list, clazz.getSuperclass());
        }
        return list;
    }

    public static List<Method> getMothds(Class<?> clazz){
    	return getMothds(clazz, false);
    }
    
    public static List<Method> getAllMothds(Class<?> clazz){
    	return getMothds(clazz, true);
    }
    
    /**
     * 获取类实例的父类的方法
     *
     * @param list  类实例的方法List
     * @param clazz 类名
     * @return List
     */
    private static List<Method> getParentClassMothds(List<Method> list, Class<?> clazz) {
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            list.add(method);
        }
        if (clazz.getSuperclass() == Object.class) {
            return list;
        }
        getParentClassMothds(list, clazz.getSuperclass());
        return list;
    }

    public static Object newInstance(Class<?> clazz) {
    		try {
				return clazz.newInstance();
			} catch (Exception e) {
				Throwables.propagate(e);
			}
    		return null;
      }
    
    public static Object newInstance(final Class<?> cls, Object[] args, Class<?>[] parameterTypes){
    	try {
			return ConstructorUtils.invokeConstructor(cls, args, parameterTypes);
		} catch (Exception e) {
			Throwables.propagate(e);
		}
		return null;
    }
    
    public static Object newInstance(final Class<?> cls, Object[] args){
    	try {
			return ConstructorUtils.invokeConstructor(cls, args);
		} catch (Exception e) {
			Throwables.propagate(e);
		}
		return null;
    }
    
}
